package com.fsnbigdata.service.impl;
import com.fsnbigdata.domain.*;
import com.fsnbigdata.domain.dto.NamingPair4;
import com.fsnbigdata.repository.SpecimenImageRepository;
import com.fsnbigdata.service.api.DocumentService;
import com.fsnbigdata.service.api.SpecimenService;

import java.util.*;

import com.fsnbigdata.util.ObjectNull;
import com.fsnbigdata.vo.NewClass;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.roo.addon.layers.service.annotations.RooServiceImpl;
import com.fsnbigdata.repository.SpecimenRepository;
import com.fsnbigdata.service.api.SpecimenDocumentService;
import com.fsnbigdata.service.api.SpecimenImageService;
import com.fsnbigdata.service.api.SpecimenVideoService;
import io.springlets.data.domain.GlobalSearch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import com.querydsl.core.types.Predicate;

/**
 * = SpecimenServiceImpl
 *
 * TODO Auto-generated class documentation
 *
 */
@RooServiceImpl(service = SpecimenService.class)
@Service
@Transactional(readOnly = true)
public class SpecimenServiceImpl implements SpecimenService {

    /**
     * TODO Auto-generated attribute documentation
     *
     */
    private SpecimenImageService specimenImageService;

    /**
     * TODO Auto-generated attribute documentation
     *
     */
    private SpecimenVideoService specimenVideoService;

    /**
     * TODO Auto-generated attribute documentation
     *
     */
    private SpecimenRepository specimenRepository;

    /**
     * TODO Auto-generated attribute documentation
     *
     */
    private SpecimenImageRepository specimenImageRepository;

    /**
     * TODO Auto-generated attribute documentation
     *
     */
    private DocumentService documentService;

    /**
     * TODO Auto-generated attribute documentation
     *
     */
    private SpecimenDocumentService specimenDocumentService;

    /**
     * TODO Auto-generated constructor documentation
     *
     * @param specimenRepository
     * @param documentService
     * @param specimenDocumentService
     * @param specimenImageService
     * @param specimenVideoService
     */
    @Autowired
    public SpecimenServiceImpl(SpecimenImageService specimenImageService, SpecimenVideoService specimenVideoService, SpecimenRepository specimenRepository, SpecimenImageRepository specimenImageRepository, DocumentService documentService, SpecimenDocumentService specimenDocumentService) {
        this.specimenImageService = specimenImageService;
        this.specimenVideoService = specimenVideoService;
        this.specimenRepository = specimenRepository;
        this.specimenImageRepository = specimenImageRepository;
        this.documentService = documentService;
        this.specimenDocumentService = specimenDocumentService;
    }

    public SpecimenImageRepository getSpecimenImageRepository() {
        return specimenImageRepository;
    }

    public void setSpecimenImageRepository(SpecimenImageRepository specimenImageRepository) {
        this.specimenImageRepository = specimenImageRepository;
    }


    /**
     * TODO Auto-generated method documentation
     *
     * @return SpecimenRepository
     */
    public SpecimenRepository getSpecimenRepository() {
        return specimenRepository;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimenRepository
     */
    public void setSpecimenRepository(SpecimenRepository specimenRepository) {
        this.specimenRepository = specimenRepository;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return DocumentService
     */
    public DocumentService getDocumentService() {
        return documentService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param documentService
     */
    public void setDocumentService(DocumentService documentService) {
        this.documentService = documentService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return SpecimenDocumentService
     */
    public SpecimenDocumentService getSpecimenDocumentService() {
        return specimenDocumentService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimenDocumentService
     */
    public void setSpecimenDocumentService(SpecimenDocumentService specimenDocumentService) {
        this.specimenDocumentService = specimenDocumentService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return SpecimenImageService
     */
    public SpecimenImageService getSpecimenImageService() {
        return specimenImageService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimenImageService
     */
    public void setSpecimenImageService(SpecimenImageService specimenImageService) {
        this.specimenImageService = specimenImageService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return SpecimenVideoService
     */
    public SpecimenVideoService getSpecimenVideoService() {
        return specimenVideoService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimenVideoService
     */
    public void setSpecimenVideoService(SpecimenVideoService specimenVideoService) {
        this.specimenVideoService = specimenVideoService;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param docsToAdd
     * @return Specimen
     */
    @Transactional
    public Specimen addToDocs(Specimen specimen, Iterable<Long> docsToAdd) {
        List<Document> docs = getDocumentService().findAll(docsToAdd);
        specimen.addToDocs(docs);
        return getSpecimenRepository().save(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param documentsToAdd
     * @return Specimen
     */
    @Transactional
    public Specimen addToDocuments(Specimen specimen, Iterable<SpecimenDocument> documentsToAdd) {
        specimen.addToDocuments(documentsToAdd);
        return getSpecimenRepository().save(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param imagesToAdd
     * @return Specimen
     */
    @Transactional
    public Specimen addToImages(Specimen specimen, Iterable<SpecimenImage> imagesToAdd) {
        specimen.addToImages(imagesToAdd);
        return getSpecimenRepository().save(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param videosToAdd
     * @return Specimen
     */
    @Transactional
    public Specimen addToVideos(Specimen specimen, Iterable<SpecimenVideo> videosToAdd) {
        specimen.addToVideos(videosToAdd);
        return getSpecimenRepository().save(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param docsToRemove
     * @return Specimen
     */
    @Transactional
    public Specimen removeFromDocs(Specimen specimen, Iterable<Long> docsToRemove) {
        List<Document> docs = getDocumentService().findAll(docsToRemove);
        specimen.removeFromDocs(docs);
        return getSpecimenRepository().save(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param documentsToRemove
     * @return Specimen
     */
    @Transactional
    public Specimen removeFromDocuments(Specimen specimen, Iterable<Long> documentsToRemove) {
        List<SpecimenDocument> documents = getSpecimenDocumentService().findAll(documentsToRemove);
        specimen.removeFromDocuments(documents);
        return getSpecimenRepository().save(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param imagesToRemove
     * @return Specimen
     */
    @Transactional
    public Specimen removeFromImages(Specimen specimen, Iterable<Long> imagesToRemove) {
        List<SpecimenImage> images = getSpecimenImageService().findAll(imagesToRemove);
        specimen.removeFromImages(images);
        return getSpecimenRepository().save(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param videosToRemove
     * @return Specimen
     */
    @Transactional
    public Specimen removeFromVideos(Specimen specimen, Iterable<Long> videosToRemove) {
        List<SpecimenVideo> videos = getSpecimenVideoService().findAll(videosToRemove);
        specimen.removeFromVideos(videos);
        return getSpecimenRepository().save(specimen);
    }

    @Override
    public List<NamingPair4> findAllByInitial(String name,String value,String initial) {
        if (StringUtils.isNotEmpty(name)&&StringUtils.isNotEmpty(value)){
            if(name.equals("DESC")&&value.equals("id")){
                //根据id进行降序排序
                return  getSpecimenRepository().findByInitialOrderByIdDesc(initial);
            }
            if(name.equals("ASC")&&value.equals("id")){
                //根据id进行升序排序
                return  getSpecimenRepository().findByInitialOrderByIdAsc(initial);
            }
            if(name.equals("DESC")&&value.equals("collectDate")){
                //根据collectDate进行降序排序
                return  getSpecimenRepository().findByInitialOrderByCollectDateDesc(initial);
            }
            if(name.equals("ASC")&&value.equals("collectDate")){
                //根据id进行升序排序
                return  getSpecimenRepository().findByInitialOrderByCollectDateAsc(initial);
            }

        }
        return getSpecimenRepository().findAllByInitial(initial);
    }

    @Override
    public List<List<Specimen>> findAllByType() {
        List<List<Specimen>> list = new ArrayList <>(  );
        for (Integer i=0;i<2;i++){
            List<Specimen> specimen = getSpecimenRepository().findAllByType( i );
            if(specimen!=null&&specimen.size()>4){
                list.add( specimen.subList( 0,4 ) ) ;
            }else {
                list.add( specimen );
            }
        }
        return list;
    }

    @Override
    public List<Specimen> findAllByType(Integer type) {
        return getSpecimenRepository().findAllByType(type);
    }

    @Override
    public Page<Specimen> findByPageAndSize(Integer type, String creator, String name, String collectDate, String collectLocation, Pageable pageable) {
        Specification<Specimen> specification=new Specification<Specimen>() {
            @Override
            public javax.persistence.criteria.Predicate toPredicate(Root<Specimen> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

                Path<String> _name=root.get("name");//关键字
                Path<String> _type=root.get("type");//类型
                Path<String> _creator=root.get("creator");//城建人
                Path<String> _collectDate=root.get("collectDate");//采集时间
                Path<String> _collectLocation=root.get("collectLocation");//采集地点

                javax.persistence.criteria.Predicate _key = criteriaBuilder.like(_name,"%"+name+"%");
                javax.persistence.criteria.Predicate _creator_key = criteriaBuilder.like(_creator,"%"+creator+"%");
                javax.persistence.criteria.Predicate _collectDate_key = criteriaBuilder.like(_collectDate,"%"+collectDate+"%");
                javax.persistence.criteria.Predicate _collectLocation_key = criteriaBuilder.like(_collectLocation,"%"+collectLocation+"%");
                javax.persistence.criteria.Predicate _type_key = criteriaBuilder.equal(_type,type);

                //当type=null时，只查关键字
                if (type==null){
                    return criteriaBuilder.and(_key);
                }

                if (StringUtils.isNotBlank(creator)||StringUtils.isNotBlank(collectDate)||StringUtils.isNotBlank(collectLocation)){

                    if (StringUtils.isNotBlank(creator)&&!creator.equals("")){
                        if(StringUtils.isNotBlank(collectDate)&&!collectDate.equals("")){
                            if(StringUtils.isNotBlank(collectLocation)&&!collectLocation.equals("")){
                                //判断采集时间、采集地点、采集人都不为空
                                return criteriaBuilder.and(_key,_type_key,_creator_key,_collectDate_key,_collectLocation_key);
                            }
                            //判断采集时间和采集人都不为空
                            return criteriaBuilder.and(_key,_type_key,_creator_key,_collectDate_key);
                        }
                        //判断采集人是否为空
                        return criteriaBuilder.and(_key,_type_key,_creator_key);
                    }
                    if (StringUtils.isNotBlank(collectDate)&&!collectDate.equals("")){
                        if(StringUtils.isNotBlank(creator)&&!creator.equals("")){
                            if(StringUtils.isNotBlank(collectLocation)&&!collectLocation.equals("")){
                                //判断采集时间、采集地点、采集人都不为空
                                return criteriaBuilder.and(_key,_type_key,_creator_key,_collectDate_key,_collectLocation_key);
                            }
                            //判断采集时间和采集人都不为空
                            return criteriaBuilder.and(_key,_type_key,_creator_key,_collectDate_key);
                        }
                        //判断采集时间是否为空
                        return criteriaBuilder.and(_key,_type_key,_collectDate_key);
                    }
                    if (StringUtils.isNotBlank(collectLocation)&&!collectLocation.equals("")){
                        if(StringUtils.isNotBlank(creator)&&!creator.equals("")){
                            if(StringUtils.isNotBlank(collectDate)&&!collectDate.equals("")){
                                //判断采集时间、采集地点、采集人都不为空
                                return criteriaBuilder.and(_key,_type_key,_creator_key,_collectDate_key,_collectLocation_key);
                            }
                            //判断采集地和采集人都不为空
                            return criteriaBuilder.and(_key,_type_key,_creator_key,_collectLocation_key);
                        }
                        //判断采集地是否为空
                        return criteriaBuilder.and(_key,_type_key,_collectLocation_key);
                    }
                }
                return criteriaBuilder.and(_key,_type_key);
            }

        };
        return getSpecimenRepository().findAll(specification,pageable);
    }

    @Override
    public List searchPageList(String name, String status,
                               String collectNumber, String collectPerson,
                               String type, String collectDate,
                               String collectLocation, Pageable pageable) {
        List list = new ArrayList(  );
        List<NewClass> specimens = new ArrayList <>(  );
        list.add( specimenRepository.queryCountByKey(name,status,collectNumber,collectPerson,type,collectDate,collectLocation));
        for (Object o:specimenRepository.queryAllByKey(name,status,collectNumber,collectPerson,type,collectDate,collectLocation,pageable)){
            Object[] objects = (Object[]) o;
            NewClass newClass = new NewClass();
            newClass.setId( ObjectNull.takeOutNull(objects[0]) );
            newClass.setName( ObjectNull.takeOutNull(objects[1]) );
            newClass.setLatin_name( ObjectNull.takeOutNull(objects[2]) );
            newClass.setNumber( ObjectNull.takeOutNull(objects[3]) );
            newClass.setLocation( ObjectNull.takeOutNull(objects[4]) );
            newClass.setCreator( ObjectNull.takeOutNull(objects[5]) );
            newClass.setNamed_info( ObjectNull.takeOutNull(objects[6]) );
            List<String> url = specimenImageRepository.getUrl( Long.parseLong( ""+objects[0] ) );
            newClass.setUrl( url.size()>0?url.get( 0 ):null );
            specimens.add( newClass );
        }
        list.add( specimens );
        return list;
    }


    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     * @param docs
     * @return Specimen
     */
    @Transactional
    public Specimen setDocs(Specimen specimen, Iterable<Long> docs) {
        List<Document> items = getDocumentService().findAll(docs);
        items.forEach(item -> {
            item.getOrganisms().size();
            item.getSpecimens().size();
        });
        Set<Document> currents = specimen.getDocs();
        Set<Document> toRemove = new HashSet<Document>();
        for (Iterator<Document> iterator = currents.iterator(); iterator.hasNext(); ) {
            Document nextDocument = iterator.next();
            if (items.contains(nextDocument)) {
                items.remove(nextDocument);
            } else {
                toRemove.add(nextDocument);
            }
        }
        specimen.removeFromDocs(toRemove);
        specimen.addToDocs(items);
        // Force the version update of the parent side to know that the parent has changed
        // because it has new books assigned
        //specimen.setVersion(specimen.getVersion() + 1);
        return getSpecimenRepository().save(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param specimen
     */
    @Transactional
    public void delete(Specimen specimen) {
        // Clear bidirectional many-to-many parent relationship with Document
        for (Document item : specimen.getDocs()) {
            item.getSpecimens().remove(specimen);
        }
        // Clear bidirectional one-to-many parent relationship with SpecimenDocument
        for (SpecimenDocument item : specimen.getDocuments()) {
            item.setSpecimen(null);
        }
        // Clear bidirectional one-to-many parent relationship with SpecimenImage
        for (SpecimenImage item : specimen.getImages()) {
            item.setSpecimen(null);
        }
        // Clear bidirectional one-to-many parent relationship with SpecimenVideo
        for (SpecimenVideo item : specimen.getVideos()) {
            item.setSpecimen(null);
        }
        getSpecimenRepository().delete(specimen);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param entities
     * @return List
     */
    @Transactional
    public List<Specimen> save(Iterable<Specimen> entities) {
        return getSpecimenRepository().save(entities);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param ids
     */
    @Transactional
    public void delete(Iterable<Long> ids) {
        List<Specimen> toDelete = getSpecimenRepository().findAll(ids);
        getSpecimenRepository().deleteInBatch(toDelete);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param entity
     * @return Specimen
     */
    @Transactional
    public Specimen save(Specimen entity) {
        entity.getImages().forEach(it -> it.setSpecimen(entity));
        entity.getVideos().forEach(it -> it.setSpecimen(entity));
        entity.getDocuments().forEach(it -> it.setSpecimen(entity));

        return getSpecimenRepository().save(entity);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param id
     * @return Specimen
     */
    public Specimen findOne(Long id) {
        return getSpecimenRepository().findOne(id);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param id
     * @return Specimen
     */
    public Specimen findOneForUpdate(Long id) {
        return getSpecimenRepository().findOneDetached(id);
    }

    @Override
    public Page<Specimen> search(Predicate predicate, Pageable pageable) {
        return getSpecimenRepository().findAll(predicate, pageable);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param ids
     * @return List
     */
    public List<Specimen> findAll(Iterable<Long> ids) {
        return getSpecimenRepository().findAll(ids);
    }


    /**
     * TODO Auto-generated method documentation
     *
     * @return List
     */
    public List<Specimen> findAll() {
        return getSpecimenRepository().findAll();
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return Long
     */
    public long count() {
        return getSpecimenRepository().count();
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param globalSearch
     * @param pageable
     * @return Page
     */
    public Page<Specimen> findAll(GlobalSearch globalSearch, Pageable pageable) {
        return getSpecimenRepository().findAll(globalSearch, pageable, null);
    }

    @Override
    public Page<Specimen> findAll(GlobalSearch globalSearch, Pageable pageable, String creator) {
        return getSpecimenRepository().findAll(globalSearch, pageable, creator);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @param ids
     * @param globalSearch
     * @param pageable
     * @return Page
     */
    public Page<Specimen> findAllByIdsIn(List<Long> ids, GlobalSearch globalSearch, Pageable pageable) {
        return getSpecimenRepository().findAllByIdsIn(ids, globalSearch, pageable);
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return Class
     */
    public Class<Specimen> getEntityType() {
        return Specimen.class;
    }

    /**
     * TODO Auto-generated method documentation
     *
     * @return Class
     */
    public Class<Long> getIdType() {
        return Long.class;
    }
}
